using System;
using System.Collections.Generic;
using System.Text;

using Mono.Cecil;

namespace CILDiffLibPrime.Collectors
{
    public class ConsoleCollector : AbstractCollector
    {
        List<MethodDefinition> m_changedMethods = new List<MethodDefinition>();
        List<MethodDefinition> m_deletedMethods = new List<MethodDefinition>();
        List<MethodDefinition> m_newMethods = new List<MethodDefinition>();
        List<FieldDefinition> m_changedFields = new List<FieldDefinition>();
        List<FieldDefinition> m_deletedFields = new List<FieldDefinition>();
        List<FieldDefinition> m_newFields = new List<FieldDefinition>();
        List<PropertyDefinition> m_changedProperties = new List<PropertyDefinition>();
        List<PropertyDefinition> m_deletedProperties = new List<PropertyDefinition>();
        List<PropertyDefinition> m_newProperties = new List<PropertyDefinition>();

        int ident = 0;
        private void IncrementIdent() { ident++; }
        private void DecrementIdent() { ident--; }
        private void PrintLine(string line)
        {
            for (int i = 0; i < ident; i++)
            {
                Console.Write("\t");
            }
            Console.WriteLine(line);
        }

        public override void OnCompareTypeBegin(TypeDefinition a, TypeDefinition b)
        {
        }

        public override void OnCompareTypeEnd(ChangeResult result, TypeDefinition a, TypeDefinition b)
        {
            if (result == ChangeResult.Changed)
            {
                PrintLine( "* " + FormatType(b) );
                IncrementIdent();
                PrintFields();
                PrintProperties();
                PrintMethods();
                DecrementIdent();
            }
            Reset();
        }

        private void Reset()
        {
            m_changedMethods = new List<MethodDefinition>();
            m_deletedMethods = new List<MethodDefinition>();
            m_newMethods = new List<MethodDefinition>();
            m_changedFields = new List<FieldDefinition>();
            m_deletedFields = new List<FieldDefinition>();
            m_newFields = new List<FieldDefinition>();
            m_changedProperties = new List<PropertyDefinition>();
            m_deletedProperties = new List<PropertyDefinition>();
            m_newProperties = new List<PropertyDefinition>();
        }

        private void PrintMethods()
        {
            if (m_deletedMethods.Count + m_newMethods.Count + m_changedMethods.Count > 0)
            {
                PrintLine("Methods");
                PrintLine("------");

                foreach (MethodDefinition method in m_deletedMethods)
                {
                    PrintLine("- " + FormatMethod(method));
                }
                foreach (MethodDefinition method in m_newMethods)
                {
                    PrintLine("+ " + FormatMethod(method));
                }
                foreach (MethodDefinition method in m_changedMethods)
                {
                    PrintLine("* " + FormatMethod(method));
                }
            }
        }

        private void PrintFields()
        {
            if (m_deletedFields.Count + m_newFields.Count + m_changedFields.Count > 0)
            {
                PrintLine("Fields");
                PrintLine("------");
                foreach (FieldDefinition field in m_deletedFields)
                {
                    PrintLine("- " + FormatField(field));
                }
                foreach (FieldDefinition field in m_newFields)
                {
                    PrintLine("+ " + FormatField(field));
                }
                foreach (FieldDefinition field in m_changedFields)
                {
                    PrintLine("* " + FormatField(field));
                }
            }
        }

        private void PrintProperties()
        {
            if (m_deletedProperties.Count + m_newProperties.Count + m_changedProperties.Count > 0)
            {
                PrintLine("Properties");
                PrintLine("------");
                foreach (PropertyDefinition property in m_deletedProperties)
                {
                    PrintLine("- " + FormatProperty(property));
                }
                foreach (PropertyDefinition property in m_newProperties)
                {
                    PrintLine("+ " + FormatProperty(property));
                }
                foreach (PropertyDefinition property in m_changedProperties)
                {
                    PrintLine("* " + FormatProperty(property));
                }
            }
        }

        public override void OnDeletedTypes(List<Mono.Cecil.TypeDefinition> types)
        {
            foreach (TypeDefinition td in types)
            {
                PrintLine("- " + FormatType(td));
            }
        }

        public override void OnNewTypes(List<Mono.Cecil.TypeDefinition> types)
        {
            foreach (TypeDefinition td in types)
            {
                PrintLine("+ " + FormatType(td));
            }
        }

        public override void OnCompareMethodBegin(MethodDefinition a, MethodDefinition b)
        {
        }

        public override void OnCompareMethodEnd(ChangeResult result, MethodDefinition a, MethodDefinition b)
        {
            if (result == ChangeResult.Changed)
            {
                m_changedMethods.Add(b);
            }
        }

        public override void OnDeletedMethods(Mono.Cecil.TypeDefinition parent, List<Mono.Cecil.MethodDefinition> methods)
        {
            m_deletedMethods = methods;
        }

        public override void OnNewMethods(List<Mono.Cecil.MethodDefinition> methods)
        {
            m_newMethods = methods;
        }

        public override void OnCompareFields(Mono.Cecil.FieldDefinition a, Mono.Cecil.FieldDefinition b)
        {
        }

        public override void OnDeletedFields(List<Mono.Cecil.FieldDefinition> fields)
        {
            m_deletedFields = fields;
        }

        public override void OnNewFields(List<Mono.Cecil.FieldDefinition> fields)
        {
            m_newFields = fields;
        }

        public override void OnCompareProperties(PropertyDefinition a, PropertyDefinition b)
        {
        }

        public override void OnDeletedProperties(List<PropertyDefinition> properties)
        {
            m_deletedProperties = properties;
        }

        public override void OnNewProperties(List<PropertyDefinition> properties)
        {
            m_newProperties = properties;
        }
    }
}
